docs(site): make the llms.txt artifacts discoverable, and fix the landing-card parser - #23336
docs(site): make the llms.txt artifacts discoverable, and fix the landing-card parser#23336bloxster wants to merge 5 commits into
Conversation
llms.txt and llms-full.txt are published but nothing points at them: they are static files, so Docusaurus never routes them, the default sitemap omits them, and no page links to them. A crawler or agent can only reach them by guessing the path, which in practice means they are never found — a browsing model asked one flag question read ~20 GitHub issue threads instead, none of which are authoritative. Advertise them three ways: - two <link rel="alternate" type="text/plain"> head tags, so every page declares where the machine-readable copies live - createSitemapItems, appending both URLs to the generated sitemap. The sibling ignorePatterns/lastmod options are closure-bound inside defaultCreateSitemapItems, so appended items are neither filtered nor double-processed and /search stays excluded - a reader-facing section on the MCP page, with a pointer from "Why using Erigon?" The section goes on the MCP page rather than "Why using Erigon?" because the latter is a card-grid landing page, whose body generate-llms.py replaces with synthesized bullets — prose added there would render on the site but never reach llms-full.txt. robots.txt is left alone: there is no standard directive for advertising llms.txt, and the Sitemap: line already there now leads to both files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dx34ND1m4ySTJXqMR8kRDX
_LANDING_CARD_RE matched a whole card with one pattern: `[^<]+` for the title and description text, `(?:.*?)` for the gaps, under re.DOTALL. `[^<]+` cannot cross a `<`, so a description containing inline markup (<strong>, <code>) fails to match where it stands — and the engine then scans forward through the permissive gap and matches the *next* card's description and </Link>, swallowing the card in between and pairing a title with the wrong description. This is live in the published corpus, on the page whose job is explaining what makes Erigon different. why-using-erigon has 11 cards; llms-full.txt carried 8: Immutable, Decentralised Data <- Staged Sync's description Flexible Pruning <- RPC Providers' description Staged Sync, RPC Providers & Large Stakers, Developers <- absent Parse in two stages instead: match each <Link> block first, then find the title and description within that block only. A card boundary is then unrepresentable, so no match can cross one. Add a count guard. This failed silently for as long as it existed because `--check` only compares generated output against committed output, which makes a systematic generator bug invariant under it: CI stays green while the corpus is wrong. The guard compares parsed cards against lp-card-title occurrences and fails loudly on a mismatch.
There was a problem hiding this comment.
Pull request overview
Improves discovery of Erigon’s LLM documentation artifacts and fixes landing-card extraction.
Changes:
- Advertises artifacts through page metadata, sitemap entries, and documentation links.
- Parses landing cards within individual
<Link>boundaries. - Adds regression tests and regenerates the full corpus.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
llms-full.txt |
Updates the repository corpus. |
docs/site/static/llms-full.txt |
Updates the deployed corpus. |
docs/site/scripts/test_generate_llms.py |
Adds parser regression tests. |
docs/site/scripts/generate-llms.py |
Fixes card parsing and adds validation. |
docs/site/docusaurus.config.ts |
Adds head and sitemap discovery. |
docs/site/docs/get-started/why-using-erigon.mdx |
Links to LLM artifacts. |
docs/site/docs/fundamentals/mcp.mdx |
Documents artifact usage. |
Suppressed comments (1)
docs/site/docusaurus.config.ts:177
- The MCP page now links both artifacts, so “Nothing else on the web links to them” is inaccurate. The relevant rationale is that static files are omitted from Docusaurus's default sitemap.
// The llms.txt artifacts live in static/, so Docusaurus never routes
// them and the default sitemap omits them. Nothing else on the web
// links to them either, which leaves them unindexable and unreachable
// by search — append them explicitly.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
yperbasis
left a comment
There was a problem hiding this comment.
Requesting changes for three correctness issues:
-
docs/site/docusaurus.config.ts: advertise/llms.txtwithrel="describedby". The llms.txt v2 proposal reservesrel="alternate" type="text/markdown"for a page-specific Markdown representation and definesrel="describedby"for the llms.txt file covering a page: https://llmstxt.org/#proposal. These site-wide aggregate files are not alternate representations of every page, and v2-aware agents may specifically look fordescribedby. Keepllms-full.txtdiscoverable through llms.txt, the visible docs, and the sitemap instead of declaring it a page-wide alternate. -
docs/site/scripts/generate-llms.py: the mismatch guard is bypassed when every card fails extraction.if not cards: return Noneruns beforeexpectedis computed, socollect_pagessilently falls back tostrip_mdx. Computeexpectedbefore the early return and add an all-malformed-grid regression test. This matches the existing unresolved thread: #23336 (comment). -
docs/site/docs/fundamentals/mcp.mdx:llms-full.txtis advertised as containing every documentation page in full, butcollect_pagesreplaces the complete body of every card-grid page with the synthesized card list. For example, the generated Why using Erigon entry omits its introduction, benefits prose, and MCP section. Preserve the non-card prose or describe this as a cleaned and synthesized corpus instead of claiming complete page contents.
Reviewed at eee030a9f1c37e951048dc8420c5af6d61fcce63. The 81 documentation-script tests, artifact check, diff check, and GitHub docs build are green.
… claims Review feedback from @yperbasis and Copilot on #23336. Five fixes. 1. Advertise llms.txt with rel="describedby", not rel="alternate". The llmstxt.org proposal defines describedby for the llms.txt file that covers a page, and reserves alternate + text/markdown for a *per-page* Markdown representation. A site-wide index is not an alternate representation of every page, and v2-aware agents look for describedby. llms-full.txt is no longer advertised in head at all: it describes no single page. It stays discoverable through llms.txt, the sitemap, and the MCP docs page. 2. Close a hole in the card-count guard. `if not cards: return None` ran before the count was taken, so a grid where *every* card failed to parse was indistinguishable from an ordinary prose page: the caller fell back to strip_mdx and the guard never ran — silently degrading the exact case it exists to catch. Count first, parse second, and return None only when the page has no cards at all. 3. Stop claiming llms-full.txt holds "every documentation page, in full". It does not: synthesize_landing replaces the whole body of a card-grid page with its card list, so why-using-erigon loses its introduction and prose. Describe the corpus as cleaned rather than verbatim, and say what is dropped. 4. Stop grouping llms.txt with llms-full.txt as "the whole documentation as one plain-text file" on why-using-erigon. llms.txt is only an index. 5. Drop "nothing else links to them" from the config comment — this PR adds the MCP page links, which makes it false. Also refresh the stated file size, 420 KB -> 430 KB.
|
@yperbasis all three addressed in 1dd741e, rebased onto your merge of 1. 2. Guard hole — confirmed before fixing. With every card malformed, 3. "Every documentation page, in full" — confirmed and materially false: Verified after the rebase: One thing worth flagging: #23335 already merged into |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (1)
docs/site/docusaurus.config.ts:100
- The PR description still promises two
rel="alternate" type="text/plain"head tags on every page, while this now emits onedescribedbylink and deliberately omitsllms-full.txt. Please either restore the advertised tags or update the description and verification so they match the shipped discovery contract.
rel: 'describedby',
href: 'https://docs.erigon.tech/llms.txt',
yperbasis
left a comment
There was a problem hiding this comment.
Requesting changes for three remaining correctness issues:
- The landing-card mismatch guard still misses cards whose title marker disappears.
- The advertised llms.txt index does not directly expose llms-full.txt.
- The new completeness wording ignores the published archived documentation versions.
Reviewed at 1dd741e8c1. Targeted validation is green: 82 documentation tests and the llms artifact drift check pass.
…, scope Follow-up review from @yperbasis on #23336. Three findings, all confirmed by reproduction before fixing. 1. The guard counted the marker it was validating. `expected` came from `lp-card-title`, so if a card lost or renamed that marker the count shrank in step with the loss it was meant to detect: verified that a two-card grid with one renamed marker emitted one bullet and raised nothing. If every marker changed, `expected` hit zero and the page fell back to strip_mdx. Count `lp-card` containers instead — the wrapper is not consumed by the parse, so the two signals stay independent. Attributes are now matched order-independently and `to=` is read separately, which the container match no longer pins down. 2. llms.txt had no route to llms-full.txt. Neither committed index contained the string at all, so once the llms-full head tag was removed, an agent following rel="describedby" reached an index with no way to find the full corpus. The generator now emits that link, and both copies are regenerated. 3. "Every documentation page" was still wrong. SECTIONS scans only docs/ and help-center/, while the site also publishes v3.3 and v3.4 from versioned_docs/ — neither artifact contains those URLs. Say current documentation, and state the exclusion outright. Two new tests: a renamed title marker must raise rather than be absorbed (verified to fail against the previous count), and card attributes must parse in either order.
…, scope Follow-up review from @yperbasis on #23336. Three findings, all confirmed by reproduction before fixing. 1. The guard counted the marker it was validating. `expected` came from `lp-card-title`, so if a card lost or renamed that marker the count shrank in step with the loss it was meant to detect: verified that a two-card grid with one renamed marker emitted one bullet and raised nothing. If every marker changed, `expected` hit zero and the page fell back to strip_mdx. Count `lp-card` containers instead — the wrapper is not consumed by the parse, so the two signals stay independent. Attributes are now matched order-independently and `to=` is read separately, which the container match no longer pins down. 2. llms.txt had no route to llms-full.txt. Neither committed index contained the string at all, so once the llms-full head tag was removed, an agent following rel="describedby" reached an index with no way to find the full corpus. The generator now emits that link, and both copies are regenerated. 3. "Every documentation page" was still wrong. SECTIONS scans only docs/ and help-center/, while the site also publishes v3.3 and v3.4 from versioned_docs/ — neither artifact contains those URLs. Say current documentation, and state the exclusion outright. Two new tests: a renamed title marker must raise rather than be absorbed (verified to fail against the previous count), and card attributes must parse in either order.
Why
docs.erigon.tech/llms.txtand/llms-full.txtare published, but nothing points anything at them. They are absent fromrobots.txt, absent fromsitemap.xml, and unlinked from every built HTML page. They are static files understatic/, so Docusaurus never routes them and the default sitemap omits them.The effect is measurable. Asked a single Erigon flag question, ChatGPT read 60 sources — roughly 8 doc pages, ~20 GitHub issue threads, 6 unrelated MCP projects, and Wikipedia's article on HTTP — and touched neither file. We are paying to generate a corpus nothing can find.
What this does
Commit 1 — discoverability.
<link rel="alternate" type="text/plain">head tags on every page advertising both.txtURLs.createSitemapItemsappends both URLs to the sitemap, preserving every default entry viadefaultCreateSitemapItems(rest).why-using-erigon.robots.txtis deliberately untouched: no standard directive advertises llms.txt, and theSitemap:line already there now leads to both files.The prose lands on
mcp.mdxrather thanwhy-using-erigon.mdxbecause the latter is a card-grid landing page whose bodysynthesize_landing()replaces wholesale — prose added there would render on the site but never reachllms-full.txt.Commit 2 — a live corpus bug found while writing the above.
_LANDING_CARD_REmatched a whole card with one pattern:[^<]+for the title and description text,(?:.*?)for the gaps, underre.DOTALL.[^<]+cannot cross a<, so a description containing inline markup (<strong>,<code>) fails to match where it stands — and the engine then scans forward through the permissive gap and matches the next card's description and</Link>, swallowing the card in between and pairing a title with the wrong description.This is live today, on the page whose job is explaining what makes Erigon different.
why-using-erigonhas 11 cards;llms-full.txtcarried 8:Fixed by parsing in two stages — match each
<Link>block first, then find title and description within that block only, which makes a card boundary unrepresentable.Plus a count guard. This failed silently for as long as it existed because
--checkonly compares generated output against committed output, which makes a systematic generator bug invariant under it: CI stays green while the corpus is wrong. The guard compares parsed cards againstlp-card-titleoccurrences and fails loudly on a mismatch.A sweep of all 8 card-grid pages confirms
why-using-erigon.mdxis the only file affected.Verification
npm ci && npm run buildclean..txt;/searchstill excluded; 73 per-pagelastmodpreserved.generate-llms.py --checkgreen; 81 tests pass.Note on branches
This is the
maincounterpart of #23335 (release/3.6). Landing it here means the change is inherited by the next release branch cut frommain, with no cutover step: both head tags and both sitemap entries use absolute site-root URLs, so nothing needs rewriting at cut time, and the parser fix plus its regression tests travel with the shared tooling.docs-deploy.ymlcurrently exists only onrelease/3.5, so neither this nor #23335 changes the live site until the 3.6 deploy switchover lands.